#include "inputdata.h"
#include <utilities/utilities.h>
#include <iostream>

InputData::InputData()
  : mNumButtons(0),
    mNumAxes(0)
{
  reset();
}

InputData::~InputData()
{
}

unsigned int InputData::numAxes() const
{
  return mNumAxes;
}

unsigned int InputData::numButtons() const
{
  return mNumButtons;
}

bool InputData::button(const std::string& name) const
{
  bool ret(false);

  int id(buttonID(name));
  if (id != -1)
  {
    ret = button(id);
  }

  return ret;
}

bool InputData::button(unsigned int id) const
{
  return mButtons.test(id);
}

bool InputData::press(const std::string& name) const
{
  bool ret(false);

  int id(buttonID(name));
  if (id != -1)
  {
    ret = press(id);
  }

  return ret;
}

bool InputData::press(unsigned int id) const
{
  return mButtons.test(id) && !mLastButtons.test(id);
}

std::list<unsigned int> InputData::press() const
{
  std::list<unsigned int> ret;

  for(unsigned int i(0); i < mNumButtons; ++i)
  {
    if (press(i))
    {
      ret.push_back(i);
    }
  }

  return ret;
}

bool InputData::release(const std::string& name) const
{
  bool ret(false);

  int id(buttonID(name));
  if (id != -1)
  {
    ret = press(id);
  }

  return ret;
}

bool InputData::release(unsigned int id) const
{
  return !mButtons.test(id) && mLastButtons.test(id);
}

std::list<unsigned int> InputData::release() const
{
  std::list<unsigned int> ret;

  for(unsigned int i(0); i < mNumButtons; ++i)
  {
    if (release(i))
    {
      ret.push_back(i);
    }
  }

  return ret;
}

int InputData::axis(const std::string& name) const
{
  int ret(0);

  int id(axisID(name));
  if (id != -1)
  {
    ret = axis(id);
  }

  return ret;
}

int InputData::axis(unsigned int id) const
{
  int ret(0);

  if (id < mNumAxes)
  {
    ret = mAxes[id];
  }

  return ret;
}

bool InputData::axisMovement(const std::string &name) const
{
  bool ret(false);

  int id(axisID(name));
  if (id != -1)
  {
    ret = axisMovement(id);
  }

  return ret;
}

bool InputData::axisMovement(unsigned int id) const
{
  bool ret(false);

  if (id < mNumAxes)
  {
    ret = mAxes[id] != mLastAxes[id];
  }

  return ret;
}

std::list<unsigned int> InputData::axisMovement() const
{
  std::list<unsigned int> ret;

  for(unsigned int i(0); i < mNumAxes; ++i)
  {
    if (axisMovement(i))
    {
      ret.push_back(i);
    }
  }

  return ret;
}

void InputData::setNumButtons(unsigned int number)
{
  if (number < mButtons.size())
  {
    mNumButtons = number;
  }
}

void InputData::setNumAxes(unsigned int number)
{
  if (number < MAX_AXES)
  {
    mNumAxes = number;
  }
}

void InputData::setButton(const std::string &name, bool pressed)
{
  int id(buttonID(name));
  if (id != -1)
  {
    setButton(id, pressed);
  }
}

void InputData::setButton(unsigned int id, bool pressed)
{
  mLastButtons.set(id, mButtons.test(id));
  mButtons.set(id, pressed);
}

void InputData::setAxis(const std::string &name, int value)
{
  int id(axisID(name));
  if (id != -1)
  {
    setAxis(id, value);
  }
}

void InputData::setAxis(unsigned int id, int value)
{
  if (id < mNumAxes)
  {
    mLastAxes[id] = mAxes[id];
    mAxes[id] = Utilities::interpolate(value, AXIS_MIN, AXIS_MAX, -100, 100);
    const int deadzone(5);
    if (-deadzone < mAxes[id] && mAxes[id] < deadzone)
    {
      mAxes[id] = 0;
    }
  }
}

void InputData::reset()
{
  mNumAxes = mNumButtons = 0;
  mButtons.reset();
  mLastButtons.reset();
  for (unsigned int i(0); i < MAX_AXES; ++i)
  {
    mLastAxes[i] = mAxes[i] = 0;
  }
}

void InputData::ack()
{
  mLastButtons = mButtons;
  for (unsigned int i(0); i < MAX_AXES; ++i)
  {
    mLastAxes[i] = mAxes[i];
  }
}

int InputData::buttonID(const std::string& name) const
{
  int ret(-1);

  ButtonMap::const_iterator it(mButtonMap.find(name));
  if (it != mButtonMap.end())
  {
    ret = it->second;
  }

  return ret;
}

int InputData::axisID(const std::string& name) const
{
  int ret(-1);

  AxisMap::const_iterator it(mAxisMap.find(name));
  if (it != mAxisMap.end())
  {
    ret = it->second;
  }

  return ret;
}

std::ostream& operator<<(std::ostream& o, const InputData& input)
{
  o << "Buttons: ";
  for (unsigned int i(0); i < input.numButtons(); ++i)
  {
    o << input.button(input.numButtons()-i-1);
  }

  o << std::endl;
  for (unsigned int i(0); i < input.numAxes(); ++i)
  {
    o << "Axis" << i << ": " << input.axis(i) << " ";
  }

  return o;
}
